package com.jet.core.service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.jet.core.enums.LoginCache;
import com.jet.core.exception.CustomException;
import com.jet.core.model.bo.LoginUser;
import com.jet.core.result.ResultCode;
import com.jet.core.utils.SecurityUtil;
import com.jet.core.utils.ServletUtil;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * @author dcl
 * @since 2024/12/12 11:12
 */
@Service
public class TokenService {

    private final RedisService<String, LoginUser> redisService;

    public TokenService(RedisService<String, LoginUser> redisService) {
        this.redisService = redisService;
    }

    public void createToken(LoginUser loginUser) {
        // 生成token
        getAccessToken(loginUser);
        getRefreshToken(loginUser);
    }

    /**
     * 获取登录token并缓存
     *
     * @param loginUser
     */
    public void getAccessToken(LoginUser loginUser) {
        String token = IdUtil.fastSimpleUUID();
        LocalDateTime loginTime = LocalDateTime.now();
        loginUser.setAccessToken(token);
        loginUser.setLoginTime(loginTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        // 根据token将loginUser缓存
        LoginCache loginCache = getTokenKey();
        String key = String.format(loginCache.getKey(), loginUser.getAccessToken());
        redisService.set(key, loginUser, loginCache.getExpire(), loginCache.getTimeUnit());
    }

    /**
     * 获取刷新token并缓存
     *
     * @param loginUser
     */
    public void getRefreshToken(LoginUser loginUser) {
        String refreshToken = IdUtil.fastSimpleUUID();
        loginUser.setRefreshToken(refreshToken);

        LoginCache loginCache = getRefreshTokenKey();
        // 根据refreshToken将loginUser缓存
        String key = String.format(loginCache.getKey(), loginUser.getRefreshToken());
        redisService.set(key, loginUser, loginCache.getExpire(), loginCache.getTimeUnit());
    }

    public void deleteToken(String token) {
        if (StrUtil.isBlank(token)) {
            return;
        }
        LoginCache loginCache = getTokenKey();
        String key = String.format(loginCache.getKey(), token);
        redisService.delete(key);
    }

    public LoginUser refreshToken(String refreshToken) {
        LoginCache refreshLoginCache = getRefreshTokenKey();
        String refreshKey = String.format(refreshLoginCache.getKey(), refreshToken);
        LoginUser loginUser = redisService.get(refreshKey);
        if (loginUser == null) {
            // 提示登录过期
            throw new CustomException(ResultCode.EXPIRE_LOGIN);
        }
        // 删除原来的token信息
        deleteToken(loginUser.getAccessToken());
        // 生成新的token
        getAccessToken(loginUser);
        // 根据refreshToken将loginUser缓存
        LoginCache loginCache = getTokenKey();
        String key = String.format(loginCache.getKey(), loginUser.getAccessToken());
        redisService.set(key, loginUser, loginCache.getExpire(), loginCache.getTimeUnit());
        return loginUser;
    }

    public String getLoginUserId() {
        LoginUser loginUser = getLoginUser();
        if (loginUser == null) {
            throw new CustomException(ResultCode.NOT_LOGIN);
        }
        return loginUser.getId();
    }

    public Long getLoginTenantId() {
        LoginUser loginUser = getLoginUser();
        if (loginUser == null) {
            throw new CustomException(ResultCode.NOT_LOGIN);
        }
        return loginUser.getMerchantNo();
    }

    public LoginUser getLoginUser() {
        HttpServletRequest request = ServletUtil.getRequest();
        if (request == null) {
            throw new CustomException("请求信息错误");
        }
        return getLoginUser(request);
    }

    public LoginUser getLoginUser(HttpServletRequest request) {
        String token = SecurityUtil.getToken(request);
        if (StrUtil.isBlank(token)) {
            throw new CustomException(ResultCode.NOT_LOGIN);
        }
        return getLoginUser(token);
    }

    public LoginUser getLoginUser(String token) {
        LoginCache loginCache = getTokenKey();
        String key = String.format(loginCache.getKey(), token);
        LoginUser loginUser = redisService.get(key);
        if (loginUser == null) {
            throw new CustomException(ResultCode.NOT_LOGIN);
        }
        return loginUser;
    }

    private LoginCache getTokenKey() {
        return LoginCache.LOGIN_CLERK_ACCESS_TOKEN;
    }

    private LoginCache getRefreshTokenKey() {
        return LoginCache.LOGIN_CLERK_REFRESH_TOKEN;
    }
}
